home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tcl7.4 / tclUtil.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-19  |  55.3 KB  |  2,156 lines

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  *    This file contains utility procedures that are used by many Tcl
  5.  *    commands.
  6.  *
  7.  * Copyright (c) 1987-1993 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. static char sccsid[] = "@(#) tclUtil.c 1.108 95/06/19 08:06:31";
  15.  
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18.  
  19. /*
  20.  * The following values are used in the flags returned by Tcl_ScanElement
  21.  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
  22.  * defined in tcl.h;  make sure its value doesn't overlap with any of the
  23.  * values below.
  24.  *
  25.  * TCL_DONT_USE_BRACES -    1 means the string mustn't be enclosed in
  26.  *                braces (e.g. it contains unmatched braces,
  27.  *                or ends in a backslash character, or user
  28.  *                just doesn't want braces);  handle all
  29.  *                special characters by adding backslashes.
  30.  * USE_BRACES -            1 means the string contains a special
  31.  *                character that can be handled simply by
  32.  *                enclosing the entire argument in braces.
  33.  * BRACES_UNMATCHED -        1 means that braces aren't properly matched
  34.  *                in the argument.
  35.  */
  36.  
  37. #define USE_BRACES        2
  38. #define BRACES_UNMATCHED    4
  39.  
  40. /*
  41.  * Function prototypes for local procedures in this file:
  42.  */
  43.  
  44. static void        SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
  45.                 int newSpace));
  46.  
  47. /*
  48.  *----------------------------------------------------------------------
  49.  *
  50.  * TclFindElement --
  51.  *
  52.  *    Given a pointer into a Tcl list, locate the first (or next)
  53.  *    element in the list.
  54.  *
  55.  * Results:
  56.  *    The return value is normally TCL_OK, which means that the
  57.  *    element was successfully located.  If TCL_ERROR is returned
  58.  *    it means that list didn't have proper list structure;
  59.  *    interp->result contains a more detailed error message.
  60.  *
  61.  *    If TCL_OK is returned, then *elementPtr will be set to point
  62.  *    to the first element of list, and *nextPtr will be set to point
  63.  *    to the character just after any white space following the last
  64.  *    character that's part of the element.  If this is the last argument
  65.  *    in the list, then *nextPtr will point to the NULL character at the
  66.  *    end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
  67.  *    the number of characters in the element.  If the element is in
  68.  *    braces, then *elementPtr will point to the character after the
  69.  *    opening brace and *sizePtr will not include either of the braces.
  70.  *    If there isn't an element in the list, *sizePtr will be zero, and
  71.  *    both *elementPtr and *termPtr will refer to the null character at
  72.  *    the end of list.  Note:  this procedure does NOT collapse backslash
  73.  *    sequences.
  74.  *
  75.  * Side effects:
  76.  *    None.
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80.  
  81. int
  82. TclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
  83.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  84.                  * If NULL, then no error message is left
  85.                  * after errors. */
  86.     register char *list;    /* String containing Tcl list with zero
  87.                  * or more elements (possibly in braces). */
  88.     char **elementPtr;        /* Fill in with location of first significant
  89.                  * character in first element of list. */
  90.     char **nextPtr;        /* Fill in with location of character just
  91.                  * after all white space following end of
  92.                  * argument (i.e. next argument or end of
  93.                  * list). */
  94.     int *sizePtr;        /* If non-zero, fill in with size of
  95.                  * element. */
  96.     int *bracePtr;        /* If non-zero fill in with non-zero/zero
  97.                  * to indicate that arg was/wasn't
  98.                  * in braces. */
  99. {
  100.     register char *p;
  101.     int openBraces = 0;
  102.     int inQuotes = 0;
  103.     int size;
  104.  
  105.     /*
  106.      * Skim off leading white space and check for an opening brace or
  107.      * quote.   Note:  use of "isascii" below and elsewhere in this
  108.      * procedure is a temporary hack (7/27/90) because Mx uses characters
  109.      * with the high-order bit set for some things.  This should probably
  110.      * be changed back eventually, or all of Tcl should call isascii.
  111.      */
  112.  
  113.     while (isspace(UCHAR(*list))) {
  114.     list++;
  115.     }
  116.     if (*list == '{') {
  117.     openBraces = 1;
  118.     list++;
  119.     } else if (*list == '"') {
  120.     inQuotes = 1;
  121.     list++;
  122.     }
  123.     if (bracePtr != 0) {
  124.     *bracePtr = openBraces;
  125.     }
  126.     p = list;
  127.  
  128.     /*
  129.      * Find the end of the element (either a space or a close brace or
  130.      * the end of the string).
  131.      */
  132.  
  133.     while (1) {
  134.     switch (*p) {
  135.  
  136.         /*
  137.          * Open brace: don't treat specially unless the element is
  138.          * in braces.  In this case, keep a nesting count.
  139.          */
  140.  
  141.         case '{':
  142.         if (openBraces != 0) {
  143.             openBraces++;
  144.         }
  145.         break;
  146.  
  147.         /*
  148.          * Close brace: if element is in braces, keep nesting
  149.          * count and quit when the last close brace is seen.
  150.          */
  151.  
  152.         case '}':
  153.         if (openBraces == 1) {
  154.             char *p2;
  155.  
  156.             size = p - list;
  157.             p++;
  158.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  159.             goto done;
  160.             }
  161.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  162.                 && (p2 < p+20); p2++) {
  163.             /* null body */
  164.             }
  165.             if (interp != NULL) {
  166.             Tcl_ResetResult(interp);
  167.             sprintf(interp->result,
  168.                 "list element in braces followed by \"%.*s\" instead of space",
  169.                 (int) (p2-p), p);
  170.             }
  171.             return TCL_ERROR;
  172.         } else if (openBraces != 0) {
  173.             openBraces--;
  174.         }
  175.         break;
  176.  
  177.         /*
  178.          * Backslash:  skip over everything up to the end of the
  179.          * backslash sequence.
  180.          */
  181.  
  182.         case '\\': {
  183.         int size;
  184.  
  185.         (void) Tcl_Backslash(p, &size);
  186.         p += size - 1;
  187.         break;
  188.         }
  189.  
  190.         /*
  191.          * Space: ignore if element is in braces or quotes;  otherwise
  192.          * terminate element.
  193.          */
  194.  
  195.         case ' ':
  196.         case '\f':
  197.         case '\n':
  198.         case '\r':
  199.         case '\t':
  200.         case '\v':
  201.         if ((openBraces == 0) && !inQuotes) {
  202.             size = p - list;
  203.             goto done;
  204.         }
  205.         break;
  206.  
  207.         /*
  208.          * Double-quote:  if element is in quotes then terminate it.
  209.          */
  210.  
  211.         case '"':
  212.         if (inQuotes) {
  213.             char *p2;
  214.  
  215.             size = p-list;
  216.             p++;
  217.             if (isspace(UCHAR(*p)) || (*p == 0)) {
  218.             goto done;
  219.             }
  220.             for (p2 = p; (*p2 != 0) && (!isspace(UCHAR(*p2)))
  221.                 && (p2 < p+20); p2++) {
  222.             /* null body */
  223.             }
  224.             if (interp != NULL) {
  225.             Tcl_ResetResult(interp);
  226.             sprintf(interp->result,
  227.                 "list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p,
  228.                 "instead of space");
  229.             }
  230.             return TCL_ERROR;
  231.         }
  232.         break;
  233.  
  234.         /*
  235.          * End of list:  terminate element.
  236.          */
  237.  
  238.         case 0:
  239.         if (openBraces != 0) {
  240.             if (interp != NULL) {
  241.             Tcl_SetResult(interp, "unmatched open brace in list",
  242.                 TCL_STATIC);
  243.             }
  244.             return TCL_ERROR;
  245.         } else if (inQuotes) {
  246.             if (interp != NULL) {
  247.             Tcl_SetResult(interp, "unmatched open quote in list",
  248.                 TCL_STATIC);
  249.             }
  250.             return TCL_ERROR;
  251.         }
  252.         size = p - list;
  253.         goto done;
  254.  
  255.     }
  256.     p++;
  257.     }
  258.  
  259.     done:
  260.     while (isspace(UCHAR(*p))) {
  261.     p++;
  262.     }
  263.     *elementPtr = list;
  264.     *nextPtr = p;
  265.     if (sizePtr != 0) {
  266.     *sizePtr = size;
  267.     }
  268.     return TCL_OK;
  269. }
  270.  
  271. /*
  272.  *----------------------------------------------------------------------
  273.  *
  274.  * TclCopyAndCollapse --
  275.  *
  276.  *    Copy a string and eliminate any backslashes that aren't in braces.
  277.  *
  278.  * Results:
  279.  *    There is no return value.  Count chars. get copied from src
  280.  *    to dst.  Along the way, if backslash sequences are found outside
  281.  *    braces, the backslashes are eliminated in the copy.
  282.  *    After scanning count chars. from source, a null character is
  283.  *    placed at the end of dst.
  284.  *
  285.  * Side effects:
  286.  *    None.
  287.  *
  288.  *----------------------------------------------------------------------
  289.  */
  290.  
  291. void
  292. TclCopyAndCollapse(count, src, dst)
  293.     int count;            /* Total number of characters to copy
  294.                  * from src. */
  295.     register char *src;        /* Copy from here... */
  296.     register char *dst;        /* ... to here. */
  297. {
  298.     register char c;
  299.     int numRead;
  300.  
  301.     for (c = *src; count > 0; src++, c = *src, count--) {
  302.     if (c == '\\') {
  303.         *dst = Tcl_Backslash(src, &numRead);
  304.         dst++;
  305.         src += numRead-1;
  306.         count -= numRead-1;
  307.     } else {
  308.         *dst = c;
  309.         dst++;
  310.     }
  311.     }
  312.     *dst = 0;
  313. }
  314.  
  315. /*
  316.  *----------------------------------------------------------------------
  317.  *
  318.  * Tcl_SplitList --
  319.  *
  320.  *    Splits a list up into its constituent fields.
  321.  *
  322.  * Results
  323.  *    The return value is normally TCL_OK, which means that
  324.  *    the list was successfully split up.  If TCL_ERROR is
  325.  *    returned, it means that "list" didn't have proper list
  326.  *    structure;  interp->result will contain a more detailed
  327.  *    error message.
  328.  *
  329.  *    *argvPtr will be filled in with the address of an array
  330.  *    whose elements point to the elements of list, in order.
  331.  *    *argcPtr will get filled in with the number of valid elements
  332.  *    in the array.  A single block of memory is dynamically allocated
  333.  *    to hold both the argv array and a copy of the list (with
  334.  *    backslashes and braces removed in the standard way).
  335.  *    The caller must eventually free this memory by calling free()
  336.  *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  337.  *    if the procedure returns normally.
  338.  *
  339.  * Side effects:
  340.  *    Memory is allocated.
  341.  *
  342.  *----------------------------------------------------------------------
  343.  */
  344.  
  345. int
  346. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  347.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. 
  348.                  * If NULL, then no error message is left. */
  349.     char *list;            /* Pointer to string with list structure. */
  350.     int *argcPtr;        /* Pointer to location to fill in with
  351.                  * the number of elements in the list. */
  352.     char ***argvPtr;        /* Pointer to place to store pointer to array
  353.                  * of pointers to list elements. */
  354. {
  355.     char **argv;
  356.     register char *p;
  357.     int size, i, result, elSize, brace;
  358.     char *element;
  359.  
  360.     /*
  361.      * Figure out how much space to allocate.  There must be enough
  362.      * space for both the array of pointers and also for a copy of
  363.      * the list.  To estimate the number of pointers needed, count
  364.      * the number of space characters in the list.
  365.      */
  366.  
  367.     for (size = 1, p = list; *p != 0; p++) {
  368.     if (isspace(UCHAR(*p))) {
  369.         size++;
  370.     }
  371.     }
  372.     size++;            /* Leave space for final NULL pointer. */
  373.     argv = (char **) ckalloc((unsigned)
  374.         ((size * sizeof(char *)) + (p - list) + 1));
  375.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  376.         *list != 0; i++) {
  377.     result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
  378.     if (result != TCL_OK) {
  379.         ckfree((char *) argv);
  380.         return result;
  381.     }
  382.     if (*element == 0) {
  383.         break;
  384.     }
  385.     if (i >= size) {
  386.         ckfree((char *) argv);
  387.         if (interp != NULL) {
  388.         Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  389.             TCL_STATIC);
  390.         }
  391.         return TCL_ERROR;
  392.     }
  393.     argv[i] = p;
  394.     if (brace) {
  395.         strncpy(p, element, (size_t) elSize);
  396.         p += elSize;
  397.         *p = 0;
  398.         p++;
  399.     } else {
  400.         TclCopyAndCollapse(elSize, element, p);
  401.         p += elSize+1;
  402.     }
  403.     }
  404.  
  405.     argv[i] = NULL;
  406.     *argvPtr = argv;
  407.     *argcPtr = i;
  408.     return TCL_OK;
  409. }
  410.  
  411. /*
  412.  *----------------------------------------------------------------------
  413.  *
  414.  * Tcl_ScanElement --
  415.  *
  416.  *    This procedure is a companion procedure to Tcl_ConvertElement.
  417.  *    It scans a string to see what needs to be done to it (e.g.
  418.  *    add backslashes or enclosing braces) to make the string into
  419.  *    a valid Tcl list element.
  420.  *
  421.  * Results:
  422.  *    The return value is an overestimate of the number of characters
  423.  *    that will be needed by Tcl_ConvertElement to produce a valid
  424.  *    list element from string.  The word at *flagPtr is filled in
  425.  *    with a value needed by Tcl_ConvertElement when doing the actual
  426.  *    conversion.
  427.  *
  428.  * Side effects:
  429.  *    None.
  430.  *
  431.  *----------------------------------------------------------------------
  432.  */
  433.  
  434. int
  435. Tcl_ScanElement(string, flagPtr)
  436.     char *string;        /* String to convert to Tcl list element. */
  437.     int *flagPtr;        /* Where to store information to guide
  438.                  * Tcl_ConvertElement. */
  439. {
  440.     int flags, nestingLevel;
  441.     register char *p;
  442.  
  443.     /*
  444.      * This procedure and Tcl_ConvertElement together do two things:
  445.      *
  446.      * 1. They produce a proper list, one that will yield back the
  447.      * argument strings when evaluated or when disassembled with
  448.      * Tcl_SplitList.  This is the most important thing.
  449.      * 
  450.      * 2. They try to produce legible output, which means minimizing the
  451.      * use of backslashes (using braces instead).  However, there are
  452.      * some situations where backslashes must be used (e.g. an element
  453.      * like "{abc": the leading brace will have to be backslashed.  For
  454.      * each element, one of three things must be done:
  455.      *
  456.      * (a) Use the element as-is (it doesn't contain anything special
  457.      * characters).  This is the most desirable option.
  458.      *
  459.      * (b) Enclose the element in braces, but leave the contents alone.
  460.      * This happens if the element contains embedded space, or if it
  461.      * contains characters with special interpretation ($, [, ;, or \),
  462.      * or if it starts with a brace or double-quote, or if there are
  463.      * no characters in the element.
  464.      *
  465.      * (c) Don't enclose the element in braces, but add backslashes to
  466.      * prevent special interpretation of special characters.  This is a
  467.      * last resort used when the argument would normally fall under case
  468.      * (b) but contains unmatched braces.  It also occurs if the last
  469.      * character of the argument is a backslash or if the element contains
  470.      * a backslash followed by newline.
  471.      *
  472.      * The procedure figures out how many bytes will be needed to store
  473.      * the result (actually, it overestimates).  It also collects information
  474.      * about the element in the form of a flags word.
  475.      */
  476.  
  477.     nestingLevel = 0;
  478.     flags = 0;
  479.     if (string == NULL) {
  480.     string = "";
  481.     }
  482.     p = string;
  483.     if ((*p == '{') || (*p == '"') || (*p == 0)) {
  484.     flags |= USE_BRACES;
  485.     }
  486.     for ( ; *p != 0; p++) {
  487.     switch (*p) {
  488.         case '{':
  489.         nestingLevel++;
  490.         break;
  491.         case '}':
  492.         nestingLevel--;
  493.         if (nestingLevel < 0) {
  494.             flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
  495.         }
  496.         break;
  497.         case '[':
  498.         case '$':
  499.         case ';':
  500.         case ' ':
  501.         case '\f':
  502.         case '\n':
  503.         case '\r':
  504.         case '\t':
  505.         case '\v':
  506.         flags |= USE_BRACES;
  507.         break;
  508.         case '\\':
  509.         if ((p[1] == 0) || (p[1] == '\n')) {
  510.             flags = TCL_DONT_USE_BRACES;
  511.         } else {
  512.             int size;
  513.  
  514.             (void) Tcl_Backslash(p, &size);
  515.             p += size-1;
  516.             flags |= USE_BRACES;
  517.         }
  518.         break;
  519.     }
  520.     }
  521.     if (nestingLevel != 0) {
  522.     flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  523.     }
  524.     *flagPtr = flags;
  525.  
  526.     /*
  527.      * Allow enough space to backslash every character plus leave
  528.      * two spaces for braces.
  529.      */
  530.  
  531.     return 2*(p-string) + 2;
  532. }
  533.  
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * Tcl_ConvertElement --
  538.  *
  539.  *    This is a companion procedure to Tcl_ScanElement.  Given the
  540.  *    information produced by Tcl_ScanElement, this procedure converts
  541.  *    a string to a list element equal to that string.
  542.  *
  543.  * Results:
  544.  *    Information is copied to *dst in the form of a list element
  545.  *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  546.  *    will produce a string identical to src).  The return value is
  547.  *    a count of the number of characters copied (not including the
  548.  *    terminating NULL character).
  549.  *
  550.  * Side effects:
  551.  *    None.
  552.  *
  553.  *----------------------------------------------------------------------
  554.  */
  555.  
  556. int
  557. Tcl_ConvertElement(src, dst, flags)
  558.     register char *src;        /* Source information for list element. */
  559.     char *dst;            /* Place to put list-ified element. */
  560.     int flags;            /* Flags produced by Tcl_ScanElement. */
  561. {
  562.     register char *p = dst;
  563.  
  564.     /*
  565.      * See the comment block at the beginning of the Tcl_ScanElement
  566.      * code for details of how this works.
  567.      */
  568.  
  569.     if ((src == NULL) || (*src == 0)) {
  570.     p[0] = '{';
  571.     p[1] = '}';
  572.     p[2] = 0;
  573.     return 2;
  574.     }
  575.     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
  576.     *p = '{';
  577.     p++;
  578.     for ( ; *src != 0; src++, p++) {
  579.         *p = *src;
  580.     }
  581.     *p = '}';
  582.     p++;
  583.     } else {
  584.     if (*src == '{') {
  585.         /*
  586.          * Can't have a leading brace unless the whole element is
  587.          * enclosed in braces.  Add a backslash before the brace.
  588.          * Furthermore, this may destroy the balance between open
  589.          * and close braces, so set BRACES_UNMATCHED.
  590.          */
  591.  
  592.         p[0] = '\\';
  593.         p[1] = '{';
  594.         p += 2;
  595.         src++;
  596.         flags |= BRACES_UNMATCHED;
  597.     }
  598.     for (; *src != 0 ; src++) {
  599.         switch (*src) {
  600.         case ']':
  601.         case '[':
  602.         case '$':
  603.         case ';':
  604.         case ' ':
  605.         case '\\':
  606.         case '"':
  607.             *p = '\\';
  608.             p++;
  609.             break;
  610.         case '{':
  611.         case '}':
  612.             /*
  613.              * It may not seem necessary to backslash braces, but
  614.              * it is.  The reason for this is that the resulting
  615.              * list element may actually be an element of a sub-list
  616.              * enclosed in braces (e.g. if Tcl_DStringStartSublist
  617.              * has been invoked), so there may be a brace mismatch
  618.              * if the braces aren't backslashed.
  619.              */
  620.  
  621.             if (flags & BRACES_UNMATCHED) {
  622.             *p = '\\';
  623.             p++;
  624.             }
  625.             break;
  626.         case '\f':
  627.             *p = '\\';
  628.             p++;
  629.             *p = 'f';
  630.             p++;
  631.             continue;
  632.         case '\n':
  633.             *p = '\\';
  634.             p++;
  635.             *p = 'n';
  636.             p++;
  637.             continue;
  638.         case '\r':
  639.             *p = '\\';
  640.             p++;
  641.             *p = 'r';
  642.             p++;
  643.             continue;
  644.         case '\t':
  645.             *p = '\\';
  646.             p++;
  647.             *p = 't';
  648.             p++;
  649.             continue;
  650.         case '\v':
  651.             *p = '\\';
  652.             p++;
  653.             *p = 'v';
  654.             p++;
  655.             continue;
  656.         }
  657.         *p = *src;
  658.         p++;
  659.     }
  660.     }
  661.     *p = '\0';
  662.     return p-dst;
  663. }
  664.  
  665. /*
  666.  *----------------------------------------------------------------------
  667.  *
  668.  * Tcl_Merge --
  669.  *
  670.  *    Given a collection of strings, merge them together into a
  671.  *    single string that has proper Tcl list structured (i.e.
  672.  *    Tcl_SplitList may be used to retrieve strings equal to the
  673.  *    original elements, and Tcl_Eval will parse the string back
  674.  *    into its original elements).
  675.  *
  676.  * Results:
  677.  *    The return value is the address of a dynamically-allocated
  678.  *    string containing the merged list.
  679.  *
  680.  * Side effects:
  681.  *    None.
  682.  *
  683.  *----------------------------------------------------------------------
  684.  */
  685.  
  686. char *
  687. Tcl_Merge(argc, argv)
  688.     int argc;            /* How many strings to merge. */
  689.     char **argv;        /* Array of string values. */
  690. {
  691. #   define LOCAL_SIZE 20
  692.     int localFlags[LOCAL_SIZE], *flagPtr;
  693.     int numChars;
  694.     char *result;
  695.     register char *dst;
  696.     int i;
  697.  
  698.     /*
  699.      * Pass 1: estimate space, gather flags.
  700.      */
  701.  
  702.     if (argc <= LOCAL_SIZE) {
  703.     flagPtr = localFlags;
  704.     } else {
  705.     flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  706.     }
  707.     numChars = 1;
  708.     for (i = 0; i < argc; i++) {
  709.     numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  710.     }
  711.  
  712.     /*
  713.      * Pass two: copy into the result area.
  714.      */
  715.  
  716.     result = (char *) ckalloc((unsigned) numChars);
  717.     dst = result;
  718.     for (i = 0; i < argc; i++) {
  719.     numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  720.     dst += numChars;
  721.     *dst = ' ';
  722.     dst++;
  723.     }
  724.     if (dst == result) {
  725.     *dst = 0;
  726.     } else {
  727.     dst[-1] = 0;
  728.     }
  729.  
  730.     if (flagPtr != localFlags) {
  731.     ckfree((char *) flagPtr);
  732.     }
  733.     return result;
  734. }
  735.  
  736. /*
  737.  *----------------------------------------------------------------------
  738.  *
  739.  * Tcl_Concat --
  740.  *
  741.  *    Concatenate a set of strings into a single large string.
  742.  *
  743.  * Results:
  744.  *    The return value is dynamically-allocated string containing
  745.  *    a concatenation of all the strings in argv, with spaces between
  746.  *    the original argv elements.
  747.  *
  748.  * Side effects:
  749.  *    Memory is allocated for the result;  the caller is responsible
  750.  *    for freeing the memory.
  751.  *
  752.  *----------------------------------------------------------------------
  753.  */
  754.  
  755. char *
  756. Tcl_Concat(argc, argv)
  757.     int argc;            /* Number of strings to concatenate. */
  758.     char **argv;        /* Array of strings to concatenate. */
  759. {
  760.     int totalSize, i;
  761.     register char *p;
  762.     char *result;
  763.  
  764.     for (totalSize = 1, i = 0; i < argc; i++) {
  765.     totalSize += strlen(argv[i]) + 1;
  766.     }
  767.     result = (char *) ckalloc((unsigned) totalSize);
  768.     if (argc == 0) {
  769.     *result = '\0';
  770.     return result;
  771.     }
  772.     for (p = result, i = 0; i < argc; i++) {
  773.     char *element;
  774.     int length;
  775.  
  776.     /*
  777.      * Clip white space off the front and back of the string
  778.      * to generate a neater result, and ignore any empty
  779.      * elements.
  780.      */
  781.  
  782.     element = argv[i];
  783.     while (isspace(UCHAR(*element))) {
  784.         element++;
  785.     }
  786.     for (length = strlen(element);
  787.         (length > 0) && (isspace(UCHAR(element[length-1])));
  788.         length--) {
  789.         /* Null loop body. */
  790.     }
  791.     if (length == 0) {
  792.         continue;
  793.     }
  794.     (void) strncpy(p, element, (size_t) length);
  795.     p += length;
  796.     *p = ' ';
  797.     p++;
  798.     }
  799.     if (p != result) {
  800.     p[-1] = 0;
  801.     } else {
  802.     *p = 0;
  803.     }
  804.     return result;
  805. }
  806.  
  807. /*
  808.  *----------------------------------------------------------------------
  809.  *
  810.  * Tcl_StringMatch --
  811.  *
  812.  *    See if a particular string matches a particular pattern.
  813.  *
  814.  * Results:
  815.  *    The return value is 1 if string matches pattern, and
  816.  *    0 otherwise.  The matching operation permits the following
  817.  *    special characters in the pattern: *?\[] (see the manual
  818.  *    entry for details on what these mean).
  819.  *
  820.  * Side effects:
  821.  *    None.
  822.  *
  823.  *----------------------------------------------------------------------
  824.  */
  825.  
  826. int
  827. Tcl_StringMatch(string, pattern)
  828.     register char *string;    /* String. */
  829.     register char *pattern;    /* Pattern, which may contain
  830.                  * special characters. */
  831. {
  832.     char c2;
  833.  
  834.     while (1) {
  835.     /* See if we're at the end of both the pattern and the string.
  836.      * If so, we succeeded.  If we're at the end of the pattern
  837.      * but not at the end of the string, we failed.
  838.      */
  839.     
  840.     if (*pattern == 0) {
  841.         if (*string == 0) {
  842.         return 1;
  843.         } else {
  844.         return 0;
  845.         }
  846.     }
  847.     if ((*string == 0) && (*pattern != '*')) {
  848.         return 0;
  849.     }
  850.  
  851.     /* Check for a "*" as the next pattern character.  It matches
  852.      * any substring.  We handle this by calling ourselves
  853.      * recursively for each postfix of string, until either we
  854.      * match or we reach the end of the string.
  855.      */
  856.     
  857.     if (*pattern == '*') {
  858.         pattern += 1;
  859.         if (*pattern == 0) {
  860.         return 1;
  861.         }
  862.         while (1) {
  863.         if (Tcl_StringMatch(string, pattern)) {
  864.             return 1;
  865.         }
  866.         if (*string == 0) {
  867.             return 0;
  868.         }
  869.         string += 1;
  870.         }
  871.     }
  872.     
  873.     /* Check for a "?" as the next pattern character.  It matches
  874.      * any single character.
  875.      */
  876.  
  877.     if (*pattern == '?') {
  878.         goto thisCharOK;
  879.     }
  880.  
  881.     /* Check for a "[" as the next pattern character.  It is followed
  882.      * by a list of characters that are acceptable, or by a range
  883.      * (two characters separated by "-").
  884.      */
  885.     
  886.     if (*pattern == '[') {
  887.         pattern += 1;
  888.         while (1) {
  889.         if ((*pattern == ']') || (*pattern == 0)) {
  890.             return 0;
  891.         }
  892.         if (*pattern == *string) {
  893.             break;
  894.         }
  895.         if (pattern[1] == '-') {
  896.             c2 = pattern[2];
  897.             if (c2 == 0) {
  898.             return 0;
  899.             }
  900.             if ((*pattern <= *string) && (c2 >= *string)) {
  901.             break;
  902.             }
  903.             if ((*pattern >= *string) && (c2 <= *string)) {
  904.             break;
  905.             }
  906.             pattern += 2;
  907.         }
  908.         pattern += 1;
  909.         }
  910.         while (*pattern != ']') {
  911.         if (*pattern == 0) {
  912.             pattern--;
  913.             break;
  914.         }
  915.         pattern += 1;
  916.         }
  917.         goto thisCharOK;
  918.     }
  919.     
  920.     /* If the next pattern character is '/', just strip off the '/'
  921.      * so we do exact matching on the character that follows.
  922.      */
  923.     
  924.     if (*pattern == '\\') {
  925.         pattern += 1;
  926.         if (*pattern == 0) {
  927.         return 0;
  928.         }
  929.     }
  930.  
  931.     /* There's no special character.  Just make sure that the next
  932.      * characters of each string match.
  933.      */
  934.     
  935.     if (*pattern != *string) {
  936.         return 0;
  937.     }
  938.  
  939.     thisCharOK: pattern += 1;
  940.     string += 1;
  941.     }
  942. }
  943.  
  944. /*
  945.  *----------------------------------------------------------------------
  946.  *
  947.  * Tcl_SetResult --
  948.  *
  949.  *    Arrange for "string" to be the Tcl return value.
  950.  *
  951.  * Results:
  952.  *    None.
  953.  *
  954.  * Side effects:
  955.  *    interp->result is left pointing either to "string" (if "copy" is 0)
  956.  *    or to a copy of string.
  957.  *
  958.  *----------------------------------------------------------------------
  959.  */
  960.  
  961. void
  962. Tcl_SetResult(interp, string, freeProc)
  963.     Tcl_Interp *interp;        /* Interpreter with which to associate the
  964.                  * return value. */
  965.     char *string;        /* Value to be returned.  If NULL,
  966.                  * the result is set to an empty string. */
  967.     Tcl_FreeProc *freeProc;    /* Gives information about the string:
  968.                  * TCL_STATIC, TCL_VOLATILE, or the address
  969.                  * of a Tcl_FreeProc such as free. */
  970. {
  971.     register Interp *iPtr = (Interp *) interp;
  972.     int length;
  973.     Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
  974.     char *oldResult = iPtr->result;
  975.  
  976.     if (string == NULL) {
  977.     iPtr->resultSpace[0] = 0;
  978.     iPtr->result = iPtr->resultSpace;
  979.     iPtr->freeProc = 0;
  980.     } else if (freeProc == TCL_DYNAMIC) {
  981.     iPtr->result = string;
  982.     iPtr->freeProc = (Tcl_FreeProc *) free;
  983.     } else if (freeProc == TCL_VOLATILE) {
  984.     length = strlen(string);
  985.     if (length > TCL_RESULT_SIZE) {
  986.         iPtr->result = (char *) ckalloc((unsigned) length+1);
  987.         iPtr->freeProc = (Tcl_FreeProc *) free;
  988.     } else {
  989.         iPtr->result = iPtr->resultSpace;
  990.         iPtr->freeProc = 0;
  991.     }
  992.     strcpy(iPtr->result, string);
  993.     } else {
  994.     iPtr->result = string;
  995.     iPtr->freeProc = freeProc;
  996.     }
  997.  
  998.     /*
  999.      * If the old result was dynamically-allocated, free it up.  Do it
  1000.      * here, rather than at the beginning, in case the new result value
  1001.      * was part of the old result value.
  1002.      */
  1003.  
  1004.     if (oldFreeProc != 0) {
  1005.     if (oldFreeProc == (Tcl_FreeProc *) free) {
  1006.         ckfree(oldResult);
  1007.     } else {
  1008.         (*oldFreeProc)(oldResult);
  1009.     }
  1010.     }
  1011. }
  1012.  
  1013. /*
  1014.  *----------------------------------------------------------------------
  1015.  *
  1016.  * Tcl_AppendResult --
  1017.  *
  1018.  *    Append a variable number of strings onto the result already
  1019.  *    present for an interpreter.
  1020.  *
  1021.  * Results:
  1022.  *    None.
  1023.  *
  1024.  * Side effects:
  1025.  *    The result in the interpreter given by the first argument
  1026.  *    is extended by the strings given by the second and following
  1027.  *    arguments (up to a terminating NULL argument).
  1028.  *
  1029.  *----------------------------------------------------------------------
  1030.  */
  1031.  
  1032.     /* VARARGS2 */
  1033. #ifndef lint
  1034. void
  1035. Tcl_AppendResult(va_alist)
  1036. #else
  1037. void
  1038.     /* VARARGS2 */ /* ARGSUSED */
  1039. Tcl_AppendResult(interp, p, va_alist)
  1040.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1041.                  * extended. */
  1042.     char *p;            /* One or more strings to add to the
  1043.                  * result, terminated with NULL. */
  1044. #endif
  1045.     va_dcl
  1046. {
  1047.     va_list argList;
  1048.     register Interp *iPtr;
  1049.     char *string;
  1050.     int newSpace;
  1051.  
  1052.     /*
  1053.      * First, scan through all the arguments to see how much space is
  1054.      * needed.
  1055.      */
  1056.  
  1057.     va_start(argList);
  1058.     iPtr = va_arg(argList, Interp *);
  1059.     newSpace = 0;
  1060.     while (1) {
  1061.     string = va_arg(argList, char *);
  1062.     if (string == NULL) {
  1063.         break;
  1064.     }
  1065.     newSpace += strlen(string);
  1066.     }
  1067.     va_end(argList);
  1068.  
  1069.     /*
  1070.      * If the append buffer isn't already setup and large enough
  1071.      * to hold the new data, set it up.
  1072.      */
  1073.  
  1074.     if ((iPtr->result != iPtr->appendResult)
  1075.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1076.         || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1077.        SetupAppendBuffer(iPtr, newSpace);
  1078.     }
  1079.  
  1080.     /*
  1081.      * Final step:  go through all the argument strings again, copying
  1082.      * them into the buffer.
  1083.      */
  1084.  
  1085.     va_start(argList);
  1086.     (void) va_arg(argList, Tcl_Interp *);
  1087.     while (1) {
  1088.     string = va_arg(argList, char *);
  1089.     if (string == NULL) {
  1090.         break;
  1091.     }
  1092.     strcpy(iPtr->appendResult + iPtr->appendUsed, string);
  1093.     iPtr->appendUsed += strlen(string);
  1094.     }
  1095.     va_end(argList);
  1096. }
  1097.  
  1098. /*
  1099.  *----------------------------------------------------------------------
  1100.  *
  1101.  * Tcl_AppendElement --
  1102.  *
  1103.  *    Convert a string to a valid Tcl list element and append it
  1104.  *    to the current result (which is ostensibly a list).
  1105.  *
  1106.  * Results:
  1107.  *    None.
  1108.  *
  1109.  * Side effects:
  1110.  *    The result in the interpreter given by the first argument
  1111.  *    is extended with a list element converted from string.  A
  1112.  *    separator space is added before the converted list element
  1113.  *    unless the current result is empty, contains the single
  1114.  *    character "{", or ends in " {".
  1115.  *
  1116.  *----------------------------------------------------------------------
  1117.  */
  1118.  
  1119. void
  1120. Tcl_AppendElement(interp, string)
  1121.     Tcl_Interp *interp;        /* Interpreter whose result is to be
  1122.                  * extended. */
  1123.     char *string;        /* String to convert to list element and
  1124.                  * add to result. */
  1125. {
  1126.     register Interp *iPtr = (Interp *) interp;
  1127.     int size, flags;
  1128.     char *dst;
  1129.  
  1130.     /*
  1131.      * See how much space is needed, and grow the append buffer if
  1132.      * needed to accommodate the list element.
  1133.      */
  1134.  
  1135.     size = Tcl_ScanElement(string, &flags) + 1;
  1136.     if ((iPtr->result != iPtr->appendResult)
  1137.         || (iPtr->appendResult[iPtr->appendUsed] != 0)
  1138.         || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1139.        SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
  1140.     }
  1141.  
  1142.     /*
  1143.      * Convert the string into a list element and copy it to the
  1144.      * buffer that's forming, with a space separator if needed.
  1145.      */
  1146.  
  1147.     dst = iPtr->appendResult + iPtr->appendUsed;
  1148.     if (TclNeedSpace(iPtr->appendResult, dst)) {
  1149.     iPtr->appendUsed++;
  1150.     *dst = ' ';
  1151.     dst++;
  1152.     }
  1153.     iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
  1154. }
  1155.  
  1156. /*
  1157.  *----------------------------------------------------------------------
  1158.  *
  1159.  * SetupAppendBuffer --
  1160.  *
  1161.  *    This procedure makes sure that there is an append buffer
  1162.  *    properly initialized for interp, and that it has at least
  1163.  *    enough room to accommodate newSpace new bytes of information.
  1164.  *
  1165.  * Results:
  1166.  *    None.
  1167.  *
  1168.  * Side effects:
  1169.  *    None.
  1170.  *
  1171.  *----------------------------------------------------------------------
  1172.  */
  1173.  
  1174. static void
  1175. SetupAppendBuffer(iPtr, newSpace)
  1176.     register Interp *iPtr;    /* Interpreter whose result is being set up. */
  1177.     int newSpace;        /* Make sure that at least this many bytes
  1178.                  * of new information may be added. */
  1179. {
  1180.     int totalSpace;
  1181.  
  1182.     /*
  1183.      * Make the append buffer larger, if that's necessary, then
  1184.      * copy the current result into the append buffer and make the
  1185.      * append buffer the official Tcl result.
  1186.      */
  1187.  
  1188.     if (iPtr->result != iPtr->appendResult) {
  1189.     /*
  1190.      * If an oversized buffer was used recently, then free it up
  1191.      * so we go back to a smaller buffer.  This avoids tying up
  1192.      * memory forever after a large operation.
  1193.      */
  1194.  
  1195.     if (iPtr->appendAvl > 500) {
  1196.         ckfree(iPtr->appendResult);
  1197.         iPtr->appendResult = NULL;
  1198.         iPtr->appendAvl = 0;
  1199.     }
  1200.     iPtr->appendUsed = strlen(iPtr->result);
  1201.     } else if (iPtr->result[iPtr->appendUsed] != 0) {
  1202.     /*
  1203.      * Most likely someone has modified a result created by
  1204.      * Tcl_AppendResult et al. so that it has a different size.
  1205.      * Just recompute the size.
  1206.      */
  1207.  
  1208.     iPtr->appendUsed = strlen(iPtr->result);
  1209.     }
  1210.     totalSpace = newSpace + iPtr->appendUsed;
  1211.     if (totalSpace >= iPtr->appendAvl) {
  1212.     char *new;
  1213.  
  1214.     if (totalSpace < 100) {
  1215.         totalSpace = 200;
  1216.     } else {
  1217.         totalSpace *= 2;
  1218.     }
  1219.     new = (char *) ckalloc((unsigned) totalSpace);
  1220.     strcpy(new, iPtr->result);
  1221.     if (iPtr->appendResult != NULL) {
  1222.         ckfree(iPtr->appendResult);
  1223.     }
  1224.     iPtr->appendResult = new;
  1225.     iPtr->appendAvl = totalSpace;
  1226.     } else if (iPtr->result != iPtr->appendResult) {
  1227.     strcpy(iPtr->appendResult, iPtr->result);
  1228.     }
  1229.     Tcl_FreeResult(iPtr);
  1230.     iPtr->result = iPtr->appendResult;
  1231. }
  1232.  
  1233. /*
  1234.  *----------------------------------------------------------------------
  1235.  *
  1236.  * Tcl_ResetResult --
  1237.  *
  1238.  *    This procedure restores the result area for an interpreter
  1239.  *    to its default initialized state, freeing up any memory that
  1240.  *    may have been allocated for the result and clearing any
  1241.  *    error information for the interpreter.
  1242.  *
  1243.  * Results:
  1244.  *    None.
  1245.  *
  1246.  * Side effects:
  1247.  *    None.
  1248.  *
  1249.  *----------------------------------------------------------------------
  1250.  */
  1251.  
  1252. void
  1253. Tcl_ResetResult(interp)
  1254.     Tcl_Interp *interp;        /* Interpreter for which to clear result. */
  1255. {
  1256.     register Interp *iPtr = (Interp *) interp;
  1257.  
  1258.     Tcl_FreeResult(iPtr);
  1259.     iPtr->result = iPtr->resultSpace;
  1260.     iPtr->resultSpace[0] = 0;
  1261.     iPtr->flags &=
  1262.         ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
  1263. }
  1264.  
  1265. /*
  1266.  *----------------------------------------------------------------------
  1267.  *
  1268.  * Tcl_SetErrorCode --
  1269.  *
  1270.  *    This procedure is called to record machine-readable information
  1271.  *    about an error that is about to be returned.
  1272.  *
  1273.  * Results:
  1274.  *    None.
  1275.  *
  1276.  * Side effects:
  1277.  *    The errorCode global variable is modified to hold all of the
  1278.  *    arguments to this procedure, in a list form with each argument
  1279.  *    becoming one element of the list.  A flag is set internally
  1280.  *    to remember that errorCode has been set, so the variable doesn't
  1281.  *    get set automatically when the error is returned.
  1282.  *
  1283.  *----------------------------------------------------------------------
  1284.  */
  1285.     /* VARARGS2 */
  1286. #ifndef lint
  1287. void
  1288. Tcl_SetErrorCode(va_alist)
  1289. #else
  1290. void
  1291.     /* VARARGS2 */ /* ARGSUSED */
  1292. Tcl_SetErrorCode(interp, p, va_alist)
  1293.     Tcl_Interp *interp;        /* Interpreter whose errorCode variable is
  1294.                  * to be set. */
  1295.     char *p;            /* One or more elements to add to errorCode,
  1296.                  * terminated with NULL. */
  1297. #endif
  1298.     va_dcl
  1299. {
  1300.     va_list argList;
  1301.     char *string;
  1302.     int flags;
  1303.     Interp *iPtr;
  1304.  
  1305.     /*
  1306.      * Scan through the arguments one at a time, appending them to
  1307.      * $errorCode as list elements.
  1308.      */
  1309.  
  1310.     va_start(argList);
  1311.     iPtr = va_arg(argList, Interp *);
  1312.     flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
  1313.     while (1) {
  1314.     string = va_arg(argList, char *);
  1315.     if (string == NULL) {
  1316.         break;
  1317.     }
  1318.     (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
  1319.         (char *) NULL, string, flags);
  1320.     flags |= TCL_APPEND_VALUE;
  1321.     }
  1322.     va_end(argList);
  1323.     iPtr->flags |= ERROR_CODE_SET;
  1324. }
  1325.  
  1326. /*
  1327.  *----------------------------------------------------------------------
  1328.  *
  1329.  * TclGetListIndex --
  1330.  *
  1331.  *    Parse a list index, which may be either an integer or the
  1332.  *    value "end".
  1333.  *
  1334.  * Results:
  1335.  *    The return value is either TCL_OK or TCL_ERROR.  If it is
  1336.  *    TCL_OK, then the index corresponding to string is left in
  1337.  *    *indexPtr.  If the return value is TCL_ERROR, then string
  1338.  *    was bogus;  an error message is returned in interp->result.
  1339.  *    If a negative index is specified, it is rounded up to 0.
  1340.  *    The index value may be larger than the size of the list
  1341.  *    (this happens when "end" is specified).
  1342.  *
  1343.  * Side effects:
  1344.  *    None.
  1345.  *
  1346.  *----------------------------------------------------------------------
  1347.  */
  1348.  
  1349. int
  1350. TclGetListIndex(interp, string, indexPtr)
  1351.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  1352.     char *string;            /* String containing list index. */
  1353.     int *indexPtr;            /* Where to store index. */
  1354. {
  1355.     if (isdigit(UCHAR(*string)) || (*string == '-')) {
  1356.     if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
  1357.         return TCL_ERROR;
  1358.     }
  1359.     if (*indexPtr < 0) {
  1360.         *indexPtr = 0;
  1361.     }
  1362.     } else if (strncmp(string, "end", strlen(string)) == 0) {
  1363.     *indexPtr = INT_MAX;
  1364.     } else {
  1365.     Tcl_AppendResult(interp, "bad index \"", string,
  1366.         "\": must be integer or \"end\"", (char *) NULL);
  1367.     return TCL_ERROR;
  1368.     }
  1369.     return TCL_OK;
  1370. }
  1371.  
  1372. /*
  1373.  *----------------------------------------------------------------------
  1374.  *
  1375.  * Tcl_RegExpCompile --
  1376.  *
  1377.  *    Compile a regular expression into a form suitable for fast
  1378.  *    matching.  This procedure retains a small cache of pre-compiled
  1379.  *    regular expressions in the interpreter, in order to avoid
  1380.  *    compilation costs as much as possible.
  1381.  *
  1382.  * Results:
  1383.  *    The return value is a pointer to the compiled form of string,
  1384.  *    suitable for passing to Tcl_RegExpExec.  This compiled form
  1385.  *    is only valid up until the next call to this procedure, so
  1386.  *    don't keep these around for a long time!  If an error occurred
  1387.  *    while compiling the pattern, then NULL is returned and an error
  1388.  *    message is left in interp->result.
  1389.  *
  1390.  * Side effects:
  1391.  *    The cache of compiled regexp's in interp will be modified to
  1392.  *    hold information for string, if such information isn't already
  1393.  *    present in the cache.
  1394.  *
  1395.  *----------------------------------------------------------------------
  1396.  */
  1397.  
  1398. Tcl_RegExp
  1399. Tcl_RegExpCompile(interp, string)
  1400.     Tcl_Interp *interp;            /* For use in error reporting. */
  1401.     char *string;            /* String for which to produce
  1402.                      * compiled regular expression. */
  1403. {
  1404.     register Interp *iPtr = (Interp *) interp;
  1405.     int i, length;
  1406.     regexp *result;
  1407.  
  1408.     length = strlen(string);
  1409.     for (i = 0; i < NUM_REGEXPS; i++) {
  1410.     if ((length == iPtr->patLengths[i])
  1411.         && (strcmp(string, iPtr->patterns[i]) == 0)) {
  1412.         /*
  1413.          * Move the matched pattern to the first slot in the
  1414.          * cache and shift the other patterns down one position.
  1415.          */
  1416.  
  1417.         if (i != 0) {
  1418.         int j;
  1419.         char *cachedString;
  1420.  
  1421.         cachedString = iPtr->patterns[i];
  1422.         result = iPtr->regexps[i];
  1423.         for (j = i-1; j >= 0; j--) {
  1424.             iPtr->patterns[j+1] = iPtr->patterns[j];
  1425.             iPtr->patLengths[j+1] = iPtr->patLengths[j];
  1426.             iPtr->regexps[j+1] = iPtr->regexps[j];
  1427.         }
  1428.         iPtr->patterns[0] = cachedString;
  1429.         iPtr->patLengths[0] = length;
  1430.         iPtr->regexps[0] = result;
  1431.         }
  1432.         return (Tcl_RegExp) iPtr->regexps[0];
  1433.     }
  1434.     }
  1435.  
  1436.     /*
  1437.      * No match in the cache.  Compile the string and add it to the
  1438.      * cache.
  1439.      */
  1440.  
  1441.     TclRegError((char *) NULL);
  1442.     result = TclRegComp(string);
  1443.     if (TclGetRegError() != NULL) {
  1444.     Tcl_AppendResult(interp,
  1445.         "couldn't compile regular expression pattern: ",
  1446.         TclGetRegError(), (char *) NULL);
  1447.     return NULL;
  1448.     }
  1449.     if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
  1450.     ckfree(iPtr->patterns[NUM_REGEXPS-1]);
  1451.     ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
  1452.     }
  1453.     for (i = NUM_REGEXPS - 2; i >= 0; i--) {
  1454.     iPtr->patterns[i+1] = iPtr->patterns[i];
  1455.     iPtr->patLengths[i+1] = iPtr->patLengths[i];
  1456.     iPtr->regexps[i+1] = iPtr->regexps[i];
  1457.     }
  1458.     iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
  1459.     strcpy(iPtr->patterns[0], string);
  1460.     iPtr->patLengths[0] = length;
  1461.     iPtr->regexps[0] = result;
  1462.     return (Tcl_RegExp) result;
  1463. }
  1464.  
  1465. /*
  1466.  *----------------------------------------------------------------------
  1467.  *
  1468.  * Tcl_RegExpExec --
  1469.  *
  1470.  *    Execute the regular expression matcher using a compiled form
  1471.  *    of a regular expression and save information about any match
  1472.  *    that is found.
  1473.  *
  1474.  * Results:
  1475.  *    If an error occurs during the matching operation then -1
  1476.  *    is returned and interp->result contains an error message.
  1477.  *    Otherwise the return value is 1 if 
  1478.  *
  1479.  * Side effects:
  1480.  *    None.
  1481.  *
  1482.  *----------------------------------------------------------------------
  1483.  */
  1484.  
  1485. int
  1486. Tcl_RegExpExec(interp, re, string, start)
  1487.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  1488.     Tcl_RegExp re;        /* Compiled regular expression;  must have
  1489.                  * been returned by previous call to
  1490.                  * Tcl_RegExpCompile. */
  1491.     char *string;        /* String against which to match re. */
  1492.     char *start;        /* If string is part of a larger string,
  1493.                  * this identifies beginning of larger
  1494.                  * string, so that "^" won't match. */
  1495. {
  1496.     int match;
  1497.  
  1498.     regexp *regexpPtr = (regexp *) re;
  1499.     TclRegError((char *) NULL);
  1500.     match = TclRegExec(regexpPtr, string, start);
  1501.     if (TclGetRegError() != NULL) {
  1502.     Tcl_ResetResult(interp);
  1503.     Tcl_AppendResult(interp, "error while matching regular expression: ",
  1504.         TclGetRegError(), (char *) NULL);
  1505.     return -1;
  1506.     }
  1507.     return match;
  1508. }
  1509.  
  1510. /*
  1511.  *----------------------------------------------------------------------
  1512.  *
  1513.  * Tcl_RegExpRange --
  1514.  *
  1515.  *    Returns pointers describing the range of a regular expression match,
  1516.  *    or one of the subranges within the match.
  1517.  *
  1518.  * Results:
  1519.  *    The variables at *startPtr and *endPtr are modified to hold the
  1520.  *    addresses of the endpoints of the range given by index.  If the
  1521.  *    specified range doesn't exist then NULLs are returned.
  1522.  *
  1523.  * Side effects:
  1524.  *    None.
  1525.  *
  1526.  *----------------------------------------------------------------------
  1527.  */
  1528.  
  1529. void
  1530. Tcl_RegExpRange(re, index, startPtr, endPtr)
  1531.     Tcl_RegExp re;        /* Compiled regular expression that has
  1532.                  * been passed to Tcl_RegExpExec. */
  1533.     int index;            /* 0 means give the range of the entire
  1534.                  * match, > 0 means give the range of
  1535.                  * a matching subrange.  Must be no greater
  1536.                  * than NSUBEXP. */
  1537.     char **startPtr;        /* Store address of first character in
  1538.                  * (sub-) range here. */
  1539.     char **endPtr;        /* Store address of character just after last
  1540.                  * in (sub-) range here. */
  1541. {
  1542.     regexp *regexpPtr = (regexp *) re;
  1543.  
  1544.     if (index >= NSUBEXP) {
  1545.     *startPtr = *endPtr = NULL;
  1546.     } else {
  1547.     *startPtr = regexpPtr->startp[index];
  1548.     *endPtr = regexpPtr->endp[index];
  1549.     }
  1550. }
  1551.  
  1552. /*
  1553.  *----------------------------------------------------------------------
  1554.  *
  1555.  * Tcl_RegExpMatch --
  1556.  *
  1557.  *    See if a string matches a regular expression.
  1558.  *
  1559.  * Results:
  1560.  *    If an error occurs during the matching operation then -1
  1561.  *    is returned and interp->result contains an error message.
  1562.  *    Otherwise the return value is 1 if "string" matches "pattern"
  1563.  *    and 0 otherwise.
  1564.  *
  1565.  * Side effects:
  1566.  *    None.
  1567.  *
  1568.  *----------------------------------------------------------------------
  1569.  */
  1570.  
  1571. int
  1572. Tcl_RegExpMatch(interp, string, pattern)
  1573.     Tcl_Interp *interp;        /* Used for error reporting. */
  1574.     char *string;        /* String. */
  1575.     char *pattern;        /* Regular expression to match against
  1576.                  * string. */
  1577. {
  1578.     Tcl_RegExp re;
  1579.  
  1580.     re = Tcl_RegExpCompile(interp, pattern);
  1581.     if (re == NULL) {
  1582.     return -1;
  1583.     }
  1584.     return Tcl_RegExpExec(interp, re, string, string);
  1585. }
  1586.  
  1587. /*
  1588.  *----------------------------------------------------------------------
  1589.  *
  1590.  * Tcl_DStringInit --
  1591.  *
  1592.  *    Initializes a dynamic string, discarding any previous contents
  1593.  *    of the string (Tcl_DStringFree should have been called already
  1594.  *    if the dynamic string was previously in use).
  1595.  *
  1596.  * Results:
  1597.  *    None.
  1598.  *
  1599.  * Side effects:
  1600.  *    The dynamic string is initialized to be empty.
  1601.  *
  1602.  *----------------------------------------------------------------------
  1603.  */
  1604.  
  1605. void
  1606. Tcl_DStringInit(dsPtr)
  1607.     register Tcl_DString *dsPtr;    /* Pointer to structure for
  1608.                      * dynamic string. */
  1609. {
  1610.     dsPtr->string = dsPtr->staticSpace;
  1611.     dsPtr->length = 0;
  1612.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1613.     dsPtr->staticSpace[0] = 0;
  1614. }
  1615.  
  1616. /*
  1617.  *----------------------------------------------------------------------
  1618.  *
  1619.  * Tcl_DStringAppend --
  1620.  *
  1621.  *    Append more characters to the current value of a dynamic string.
  1622.  *
  1623.  * Results:
  1624.  *    The return value is a pointer to the dynamic string's new value.
  1625.  *
  1626.  * Side effects:
  1627.  *    Length bytes from string (or all of string if length is less
  1628.  *    than zero) are added to the current value of the string.  Memory
  1629.  *    gets reallocated if needed to accomodate the string's new size.
  1630.  *
  1631.  *----------------------------------------------------------------------
  1632.  */
  1633.  
  1634. char *
  1635. Tcl_DStringAppend(dsPtr, string, length)
  1636.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1637.                      * string. */
  1638.     char *string;            /* String to append.  If length is
  1639.                      * -1 then this must be
  1640.                      * null-terminated. */
  1641.     int length;                /* Number of characters from string
  1642.                      * to append.  If < 0, then append all
  1643.                      * of string, up to null at end. */
  1644. {
  1645.     int newSize;
  1646.     char *newString, *dst, *end;
  1647.  
  1648.     if (length < 0) {
  1649.     length = strlen(string);
  1650.     }
  1651.     newSize = length + dsPtr->length;
  1652.  
  1653.     /*
  1654.      * Allocate a larger buffer for the string if the current one isn't
  1655.      * large enough.  Allocate extra space in the new buffer so that there
  1656.      * will be room to grow before we have to allocate again.
  1657.      */
  1658.  
  1659.     if (newSize >= dsPtr->spaceAvl) {
  1660.     dsPtr->spaceAvl = newSize*2;
  1661.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1662.     memcpy((VOID *)newString, (VOID *) dsPtr->string,
  1663.         (size_t) dsPtr->length);
  1664.     if (dsPtr->string != dsPtr->staticSpace) {
  1665.         ckfree(dsPtr->string);
  1666.     }
  1667.     dsPtr->string = newString;
  1668.     }
  1669.  
  1670.     /*
  1671.      * Copy the new string into the buffer at the end of the old
  1672.      * one.
  1673.      */
  1674.  
  1675.     for (dst = dsPtr->string + dsPtr->length, end = string+length;
  1676.         string < end; string++, dst++) {
  1677.     *dst = *string;
  1678.     }
  1679.     *dst = 0;
  1680.     dsPtr->length += length;
  1681.     return dsPtr->string;
  1682. }
  1683.  
  1684. /*
  1685.  *----------------------------------------------------------------------
  1686.  *
  1687.  * Tcl_DStringAppendElement --
  1688.  *
  1689.  *    Append a list element to the current value of a dynamic string.
  1690.  *
  1691.  * Results:
  1692.  *    The return value is a pointer to the dynamic string's new value.
  1693.  *
  1694.  * Side effects:
  1695.  *    String is reformatted as a list element and added to the current
  1696.  *    value of the string.  Memory gets reallocated if needed to
  1697.  *    accomodate the string's new size.
  1698.  *
  1699.  *----------------------------------------------------------------------
  1700.  */
  1701.  
  1702. char *
  1703. Tcl_DStringAppendElement(dsPtr, string)
  1704.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1705.                      * string. */
  1706.     char *string;            /* String to append.  Must be
  1707.                      * null-terminated. */
  1708. {
  1709.     int newSize, flags;
  1710.     char *dst, *newString;
  1711.  
  1712.     newSize = Tcl_ScanElement(string, &flags) + dsPtr->length + 1;
  1713.  
  1714.     /*
  1715.      * Allocate a larger buffer for the string if the current one isn't
  1716.      * large enough.  Allocate extra space in the new buffer so that there
  1717.      * will be room to grow before we have to allocate again.
  1718.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1719.      * to a larger buffer, since there may be embedded NULLs in the
  1720.      * string in some cases.
  1721.      */
  1722.  
  1723.     if (newSize >= dsPtr->spaceAvl) {
  1724.     dsPtr->spaceAvl = newSize*2;
  1725.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1726.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1727.         (size_t) dsPtr->length);
  1728.     if (dsPtr->string != dsPtr->staticSpace) {
  1729.         ckfree(dsPtr->string);
  1730.     }
  1731.     dsPtr->string = newString;
  1732.     }
  1733.  
  1734.     /*
  1735.      * Convert the new string to a list element and copy it into the
  1736.      * buffer at the end, with a space, if needed.
  1737.      */
  1738.  
  1739.     dst = dsPtr->string + dsPtr->length;
  1740.     if (TclNeedSpace(dsPtr->string, dst)) {
  1741.     *dst = ' ';
  1742.     dst++;
  1743.     dsPtr->length++;
  1744.     }
  1745.     dsPtr->length += Tcl_ConvertElement(string, dst, flags);
  1746.     return dsPtr->string;
  1747. }
  1748.  
  1749. /*
  1750.  *----------------------------------------------------------------------
  1751.  *
  1752.  * Tcl_DStringSetLength --
  1753.  *
  1754.  *    Change the length of a dynamic string.  This can cause the
  1755.  *    string to either grow or shrink, depending on the value of
  1756.  *    length.
  1757.  *
  1758.  * Results:
  1759.  *    None.
  1760.  *
  1761.  * Side effects:
  1762.  *    The length of dsPtr is changed to length and a null byte is
  1763.  *    stored at that position in the string.  If length is larger
  1764.  *    than the space allocated for dsPtr, then a panic occurs.
  1765.  *
  1766.  *----------------------------------------------------------------------
  1767.  */
  1768.  
  1769. void
  1770. Tcl_DStringSetLength(dsPtr, length)
  1771.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1772.                      * string. */
  1773.     int length;                /* New length for dynamic string. */
  1774. {
  1775.     if (length < 0) {
  1776.     length = 0;
  1777.     }
  1778.     if (length >= dsPtr->spaceAvl) {
  1779.     char *newString;
  1780.  
  1781.     dsPtr->spaceAvl = length+1;
  1782.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1783.  
  1784.     /*
  1785.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1786.      * to a larger buffer, since there may be embedded NULLs in the
  1787.      * string in some cases.
  1788.      */
  1789.  
  1790.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1791.         (size_t) dsPtr->length);
  1792.     if (dsPtr->string != dsPtr->staticSpace) {
  1793.         ckfree(dsPtr->string);
  1794.     }
  1795.     dsPtr->string = newString;
  1796.     }
  1797.     dsPtr->length = length;
  1798.     dsPtr->string[length] = 0;
  1799. }
  1800.  
  1801. /*
  1802.  *----------------------------------------------------------------------
  1803.  *
  1804.  * Tcl_DStringFree --
  1805.  *
  1806.  *    Frees up any memory allocated for the dynamic string and
  1807.  *    reinitializes the string to an empty state.
  1808.  *
  1809.  * Results:
  1810.  *    None.
  1811.  *
  1812.  * Side effects:
  1813.  *    The previous contents of the dynamic string are lost, and
  1814.  *    the new value is an empty string.
  1815.  *
  1816.  *----------------------------------------------------------------------
  1817.  */
  1818.  
  1819. void
  1820. Tcl_DStringFree(dsPtr)
  1821.     register Tcl_DString *dsPtr;    /* Structure describing dynamic
  1822.                      * string. */
  1823. {
  1824.     if (dsPtr->string != dsPtr->staticSpace) {
  1825.     ckfree(dsPtr->string);
  1826.     }
  1827.     dsPtr->string = dsPtr->staticSpace;
  1828.     dsPtr->length = 0;
  1829.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1830.     dsPtr->staticSpace[0] = 0;
  1831. }
  1832.  
  1833. /*
  1834.  *----------------------------------------------------------------------
  1835.  *
  1836.  * Tcl_DStringResult --
  1837.  *
  1838.  *    This procedure moves the value of a dynamic string into an
  1839.  *    interpreter as its result.  The string itself is reinitialized
  1840.  *    to an empty string.
  1841.  *
  1842.  * Results:
  1843.  *    None.
  1844.  *
  1845.  * Side effects:
  1846.  *    The string is "moved" to interp's result, and any existing
  1847.  *    result for interp is freed up.  DsPtr is reinitialized to
  1848.  *    an empty string.
  1849.  *
  1850.  *----------------------------------------------------------------------
  1851.  */
  1852.  
  1853. void
  1854. Tcl_DStringResult(interp, dsPtr)
  1855.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1856.                      * reset. */
  1857.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1858.                      * the result of interp. */
  1859. {
  1860.     Tcl_ResetResult(interp);
  1861.     if (dsPtr->string != dsPtr->staticSpace) {
  1862.     interp->result = dsPtr->string;
  1863.     interp->freeProc = (Tcl_FreeProc *) free;
  1864.     } else if (dsPtr->length < TCL_RESULT_SIZE) {
  1865.     interp->result = ((Interp *) interp)->resultSpace;
  1866.     strcpy(interp->result, dsPtr->string);
  1867.     } else {
  1868.     Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
  1869.     }
  1870.     dsPtr->string = dsPtr->staticSpace;
  1871.     dsPtr->length = 0;
  1872.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1873.     dsPtr->staticSpace[0] = 0;
  1874. }
  1875.  
  1876. /*
  1877.  *----------------------------------------------------------------------
  1878.  *
  1879.  * Tcl_DStringGetResult --
  1880.  *
  1881.  *    This procedure moves the result of an interpreter into a
  1882.  *    dynamic string.
  1883.  *
  1884.  * Results:
  1885.  *    None.
  1886.  *
  1887.  * Side effects:
  1888.  *    The interpreter's result is cleared, and the previous contents
  1889.  *    of dsPtr are freed.
  1890.  *
  1891.  *----------------------------------------------------------------------
  1892.  */
  1893.  
  1894. void
  1895. Tcl_DStringGetResult(interp, dsPtr)
  1896.     Tcl_Interp *interp;            /* Interpreter whose result is to be
  1897.                      * reset. */
  1898.     Tcl_DString *dsPtr;            /* Dynamic string that is to become
  1899.                      * the result of interp. */
  1900. {
  1901.     Interp *iPtr = (Interp *) interp;
  1902.     if (dsPtr->string != dsPtr->staticSpace) {
  1903.     ckfree(dsPtr->string);
  1904.     }
  1905.     dsPtr->length = strlen(iPtr->result);
  1906.     if (iPtr->freeProc != NULL) {
  1907.     if (iPtr->freeProc == (Tcl_FreeProc *) free) {
  1908.         dsPtr->string = iPtr->result;
  1909.         dsPtr->spaceAvl = dsPtr->length+1;
  1910.     } else {
  1911.         dsPtr->string = ckalloc((unsigned) (dsPtr->length+1));
  1912.         strcpy(dsPtr->string, iPtr->result);
  1913.         (*iPtr->freeProc)(iPtr->result);
  1914.     }
  1915.     dsPtr->spaceAvl = dsPtr->length+1;
  1916.     iPtr->freeProc = NULL;
  1917.     } else {
  1918.     if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
  1919.         dsPtr->string = dsPtr->staticSpace;
  1920.         dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1921.     } else {
  1922.         dsPtr->string = ckalloc((unsigned) (dsPtr->length + 1));
  1923.         dsPtr->spaceAvl = dsPtr->length + 1;
  1924.     }
  1925.     strcpy(dsPtr->string, iPtr->result);
  1926.     }
  1927.     iPtr->result = iPtr->resultSpace;
  1928.     iPtr->resultSpace[0] = 0;
  1929. }
  1930.  
  1931. /*
  1932.  *----------------------------------------------------------------------
  1933.  *
  1934.  * Tcl_DStringStartSublist --
  1935.  *
  1936.  *    This procedure adds the necessary information to a dynamic
  1937.  *    string (e.g. " {" to start a sublist.  Future element
  1938.  *    appends will be in the sublist rather than the main list.
  1939.  *
  1940.  * Results:
  1941.  *    None.
  1942.  *
  1943.  * Side effects:
  1944.  *    Characters get added to the dynamic string.
  1945.  *
  1946.  *----------------------------------------------------------------------
  1947.  */
  1948.  
  1949. void
  1950. Tcl_DStringStartSublist(dsPtr)
  1951.     Tcl_DString *dsPtr;            /* Dynamic string. */
  1952. {
  1953.     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
  1954.     Tcl_DStringAppend(dsPtr, " {", -1);
  1955.     } else {
  1956.     Tcl_DStringAppend(dsPtr, "{", -1);
  1957.     }
  1958. }
  1959.  
  1960. /*
  1961.  *----------------------------------------------------------------------
  1962.  *
  1963.  * Tcl_DStringEndSublist --
  1964.  *
  1965.  *    This procedure adds the necessary characters to a dynamic
  1966.  *    string to end a sublist (e.g. "}").  Future element appends
  1967.  *    will be in the enclosing (sub)list rather than the current
  1968.  *    sublist.
  1969.  *
  1970.  * Results:
  1971.  *    None.
  1972.  *
  1973.  * Side effects:
  1974.  *    None.
  1975.  *
  1976.  *----------------------------------------------------------------------
  1977.  */
  1978.  
  1979. void
  1980. Tcl_DStringEndSublist(dsPtr)
  1981.     Tcl_DString *dsPtr;            /* Dynamic string. */
  1982. {
  1983.     Tcl_DStringAppend(dsPtr, "}", -1);
  1984. }
  1985.  
  1986. /*
  1987.  *----------------------------------------------------------------------
  1988.  *
  1989.  * Tcl_PrintDouble --
  1990.  *
  1991.  *    Given a floating-point value, this procedure converts it to
  1992.  *    an ASCII string using.
  1993.  *
  1994.  * Results:
  1995.  *    The ASCII equivalent of "value" is written at "dst".  It is
  1996.  *    written using the current precision, and it is guaranteed to
  1997.  *    contain a decimal point or exponent, so that it looks like
  1998.  *    a floating-point value and not an integer.
  1999.  *
  2000.  * Side effects:
  2001.  *    None.
  2002.  *
  2003.  *----------------------------------------------------------------------
  2004.  */
  2005.  
  2006. void
  2007. Tcl_PrintDouble(interp, value, dst)
  2008.     Tcl_Interp *interp;            /* Interpreter whose tcl_precision
  2009.                      * variable controls printing. */
  2010.     double value;            /* Value to print as string. */
  2011.     char *dst;                /* Where to store converted value;
  2012.                      * must have at least TCL_DOUBLE_SPACE
  2013.                      * characters. */
  2014. {
  2015.     register char *p;
  2016.     sprintf(dst, ((Interp *) interp)->pdFormat, value);
  2017.  
  2018.     /*
  2019.      * If the ASCII result looks like an integer, add ".0" so that it
  2020.      * doesn't look like an integer anymore.  This prevents floating-point
  2021.      * values from being converted to integers unintentionally.
  2022.      */
  2023.  
  2024.     for (p = dst; *p != 0; p++) {
  2025.     if ((*p == '.') || (isalpha(UCHAR(*p)))) {
  2026.         return;
  2027.     }
  2028.     }
  2029.     p[0] = '.';
  2030.     p[1] = '0';
  2031.     p[2] = 0;
  2032. }
  2033.  
  2034. /*
  2035.  *----------------------------------------------------------------------
  2036.  *
  2037.  * TclPrecTraceProc --
  2038.  *
  2039.  *    This procedure is invoked whenever the variable "tcl_precision"
  2040.  *    is written.
  2041.  *
  2042.  * Results:
  2043.  *    Returns NULL if all went well, or an error message if the
  2044.  *    new value for the variable doesn't make sense.
  2045.  *
  2046.  * Side effects:
  2047.  *    If the new value doesn't make sense then this procedure
  2048.  *    undoes the effect of the variable modification.  Otherwise
  2049.  *    it modifies the format string that's used by Tcl_PrintDouble.
  2050.  *
  2051.  *----------------------------------------------------------------------
  2052.  */
  2053.  
  2054.     /* ARGSUSED */
  2055. char *
  2056. TclPrecTraceProc(clientData, interp, name1, name2, flags)
  2057.     ClientData clientData;    /* Not used. */
  2058.     Tcl_Interp *interp;        /* Interpreter containing variable. */
  2059.     char *name1;        /* Name of variable. */
  2060.     char *name2;        /* Second part of variable name. */
  2061.     int flags;            /* Information about what happened. */
  2062. {
  2063.     register Interp *iPtr = (Interp *) interp;
  2064.     char *value, *end;
  2065.     int prec;
  2066.  
  2067.     /*
  2068.      * If the variable is unset, then recreate the trace and restore
  2069.      * the default value of the format string.
  2070.      */
  2071.  
  2072.     if (flags & TCL_TRACE_UNSETS) {
  2073.     if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
  2074.         Tcl_TraceVar2(interp, name1, name2,
  2075.             TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  2076.             TclPrecTraceProc, clientData);
  2077.     }
  2078.     strcpy(iPtr->pdFormat, DEFAULT_PD_FORMAT);
  2079.     iPtr->pdPrec = DEFAULT_PD_PREC;
  2080.     return (char *) NULL;
  2081.     }
  2082.  
  2083.     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
  2084.     if (value == NULL) {
  2085.     value = "";
  2086.     }
  2087.     prec = strtoul(value, &end, 10);
  2088.     if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
  2089.         (end == value) || (*end != 0)) {
  2090.     char oldValue[10];
  2091.  
  2092.     sprintf(oldValue, "%d", iPtr->pdPrec);
  2093.     Tcl_SetVar2(interp, name1, name2, oldValue, flags & TCL_GLOBAL_ONLY);
  2094.     return "improper value for precision";
  2095.     }
  2096.     sprintf(iPtr->pdFormat, "%%.%dg", prec);
  2097.     iPtr->pdPrec = prec;
  2098.     return (char *) NULL;
  2099. }
  2100.  
  2101. /*
  2102.  *----------------------------------------------------------------------
  2103.  *
  2104.  * TclNeedSpace --
  2105.  *
  2106.  *    This procedure checks to see whether it is appropriate to
  2107.  *    add a space before appending a new list element to an
  2108.  *    existing string.
  2109.  *
  2110.  * Results:
  2111.  *    The return value is 1 if a space is appropriate, 0 otherwise.
  2112.  *
  2113.  * Side effects:
  2114.  *    None.
  2115.  *
  2116.  *----------------------------------------------------------------------
  2117.  */
  2118.  
  2119. int
  2120. TclNeedSpace(start, end)
  2121.     char *start;        /* First character in string. */
  2122.     char *end;            /* End of string (place where space will
  2123.                  * be added, if appropriate). */
  2124. {
  2125.     /*
  2126.      * A space is needed unless either
  2127.      * (a) we're at the start of the string, or
  2128.      * (b) the trailing characters of the string consist of one or more
  2129.      *     open curly braces preceded by a space or extending back to
  2130.      *     the beginning of the string.
  2131.      * (c) the trailing characters of the string consist of a space
  2132.      *       preceded by a character other than backslash.
  2133.      */
  2134.  
  2135.     if (end == start) {
  2136.     return 0;
  2137.     }
  2138.     end--;
  2139.     if (*end != '{') {
  2140.     if (isspace(UCHAR(*end)) && ((end == start) || (end[-1] != '\\'))) {
  2141.         return 0;
  2142.     }
  2143.     return 1;
  2144.     }
  2145.     do {
  2146.     if (end == start) {
  2147.         return 0;
  2148.     }
  2149.     end--;
  2150.     } while (*end == '{');
  2151.     if (isspace(UCHAR(*end))) {
  2152.     return 0;
  2153.     }
  2154.     return 1;
  2155. }
  2156.